#ifndef DW_GRAPHICS_MESH_H
# define DW_GRAPHICS_MESH_H

#	include "graphics/object.h"
#include "graphics/renderer.h"

namespace dw
{
namespace graphics
{

class SubMesh;
class VertexBuffer;
class IndexBuffer;
class Skeleton;

class Mesh : public Object
{
// Constructors
public:

	Mesh();
	
	virtual ~Mesh();

// Methods
public:

	virtual Type getType() const ;

	unsigned getNumSubMeshes() const	{ return static_cast< unsigned >(_subMeshes.size()); }

	SubMesh* getSubMesh(const unsigned i) const { dwAssert(i < _subMeshes.size(), "Index is out of range"); return _subMeshes[i]; }

	VertexBuffer* getVertexBuffer() const { return _vertexBuffer; }

	IndexBuffer* getIndexBuffer() const { return _indexBuffer;  }

	Skeleton* getSkeleton() const { return _skeleton; }



	void setVertexBuffer(VertexBuffer* vertexBuffer) { _vertexBuffer = vertexBuffer; }

	void setIndexBuffer(IndexBuffer* indexBuffer) { _indexBuffer = indexBuffer; }

	void setSkeleton(Skeleton* skeleton) { _skeleton = skeleton; }



	SubMesh* createSubMesh(primitive::types primitiveType, 
		const uint32 indexStart, 
		const uint32 numIndices,
		const uint32 vertexIndexStart, 
		const uint32 vertexIndexEnd, 
		const std::string& materialName);

	void addSubMesh(SubMesh* subMesh);

	void removeSubMesh(const unsigned i);

	void optimize();
	
	/// Render the entire mesh.
	virtual void render() const ;

	//virtual void accept(const MeshVisitor& meshVisitor);

	virtual bool intersects(const Ray& ray)	const { return false; }



	const bool isSkinned() { return _skinned; }



	static Mesh* sphere(const float radius, const int slices, const int stacks);

	static Mesh* cylinder(const float radius, const float height);

	static Mesh* torus(const float radius);

protected:

	typedef std::vector< SubMesh* >					SubMeshArray;

	typedef SubMeshArray::iterator SubMeshIterator;

	typedef SubMeshArray::const_iterator SubMeshConstIterator;

// Fields
protected:

	VertexBuffer* _vertexBuffer;

	IndexBuffer* _indexBuffer;

	SubMeshArray _subMeshes;

	Skeleton* _skeleton;

	bool _skinned;
	
// Friends
private:
	
	friend	
	std::ostream& operator<<(std::ostream&, const Mesh&);
	
	friend
	std::istream& operator>>	(std::istream&, Mesh&);
};

} // namespace graphics
} // namespace dw

#endif // !DW_GRAPHICS_MESH_H
